namespace Terra.Core.Common.ErrorCodes.Registration;

using System.Reflection;
using Terra.Core.Common.ErrorCodes.Attributes;
using Terra.Core.Common.ErrorCodes.Models;
using Terra.Core.Common.ErrorCodes.Providers;

/// <summary>
/// 错误码注册器
/// </summary>
public static class ErrorCodeRegistration
{
    /// <summary>
    /// 从程序集注册错误码
    /// </summary>
    /// <param name="provider">错误码提供者</param>
    /// <param name="assemblies">要扫描的程序集集合</param>
    public static void RegisterFromAssemblies(IErrorCodeProvider provider, params Assembly[] assemblies)
    {
        foreach (var assembly in assemblies)
        {
            RegisterFromAssembly(provider, assembly);
        }
    }

    /// <summary>
    /// 从程序集注册错误码
    /// </summary>
    /// <param name="provider">错误码提供者</param>
    /// <param name="assembly">要扫描的程序集</param>
    public static void RegisterFromAssembly(IErrorCodeProvider provider, Assembly assembly)
    {
        var types = assembly.GetTypes()
            .Where(t => t.IsClass && !t.IsAbstract && t.IsPublic);

        foreach (var type in types)
        {
            RegisterFromType(provider, type);
        }
    }

    /// <summary>
    /// 从类型注册错误码
    /// </summary>
    /// <param name="provider">错误码提供者</param>
    /// <param name="type">要扫描的类型</param>
    public static void RegisterFromType(IErrorCodeProvider provider, Type type)
    {
        var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);

        foreach (var field in fields)
        {
            var attribute = field.GetCustomAttribute<ErrorCodeAttribute>();
            if (attribute == null)
            {
                continue;
            }

            // 验证错误码值与字段值是否匹配
            if (field.GetValue(null) is string fieldValue && fieldValue != attribute.Code)
            {
                throw new InvalidOperationException(
                    $"错误码值不匹配: 类型 {type.FullName} 中的字段 {field.Name} 值为 {fieldValue}，" +
                    $"但特性定义的错误码为 {attribute.Code}");
            }

            // 注册错误码
            var errorCodeInfo = attribute.ToErrorCodeInfo();
            provider.RegisterErrorCode(attribute.Code, errorCodeInfo);
        }
    }

    /// <summary>
    /// 验证错误码是否重复
    /// </summary>
    /// <param name="provider">错误码提供者</param>
    public static void ValidateErrorCodes(IErrorCodeProvider provider)
    {
        var errorCodes = provider.GetAllErrorCodes();
        var duplicates = errorCodes
            .GroupBy(x => x.Key)
            .Where(g => g.Count() > 1)
            .Select(g => g.Key)
            .ToList();

        if (duplicates.Any())
        {
            throw new InvalidOperationException(
                $"发现重复的错误码: {string.Join(", ", duplicates)}");
        }
    }
}